home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / bbs / termv4.6 / extras / source / term-source.lha / FileBuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-18  |  21.3 KB  |  1,116 lines

  1. /*
  2. **    FileBuffer.c
  3. **
  4. **    Double-buffered file I/O routines
  5. **
  6. **    Copyright © 1990-1996 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #ifndef _GLOBAL_H
  11. #include "Global.h"
  12. #endif
  13.  
  14.     /* Argument types. */
  15.  
  16. enum    {    ARG_NAME,ARG_MODE };
  17. enum    {    ARG_OFFSET,ARG_ORIGIN };
  18.  
  19.     /* Seek offsets. */
  20.  
  21. enum    {    SEEKFILE_SET,SEEKFILE_CURR,SEEKFILE_END };
  22.  
  23.     /* Command codes. */
  24.  
  25. enum    {    BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
  26.  
  27.     /* ObtainInfo(struct Buffer *File):
  28.      *
  29.      *    Obtain information on the disk a buffered file
  30.      *    resides on.
  31.      */
  32.  
  33. STATIC VOID
  34. ObtainInfo(struct Buffer *File)
  35. {
  36.         /* Lock on the path available? */
  37.  
  38.     if(File -> InfoPort)
  39.     {
  40.             /* This is more or less a trick; we try to obtain
  41.              * information on a filing system without having a
  42.              * shared lock on it. We cannot DupLockFromFH()
  43.              * the file handle since it was allocated for
  44.              * exclusive access. The ACTION_DISK_INFO packet
  45.              * solves this problem as it requires only the
  46.              * filing system task (MsgPort) to be given.
  47.              */
  48.  
  49.         if(!DoPkt1(File -> InfoPort,ACTION_DISK_INFO,MKBADDR(&File -> InfoData)))
  50.         {
  51.             File -> InfoData . id_NumBlocks        = 0;
  52.             File -> InfoData . id_BytesPerBlock    = 0;
  53.         }
  54.     }
  55. }
  56.  
  57.     /* FileBufferServer():
  58.      *
  59.      *    Background process to handle the buffering
  60.      *    of a filehandle, automatically gets invoked
  61.      *    when a file is opened.
  62.      */
  63.  
  64. STATIC VOID __saveds
  65. FileBufferServer(VOID)
  66. {
  67.     struct MsgPort    *Port;
  68.     struct Buffer    *Buffer;
  69.     BOOL         Terminated = FALSE,
  70.              Done,
  71.              WasFull;
  72.     UBYTE        *String;
  73.     APTR         Data;
  74.     LONG         Length;
  75.     BPTR         SomeLock;
  76.     struct Process    *Me;
  77.  
  78.         /* Wait for startup message (-> Buffer). */
  79.  
  80.     Me = (struct Process *)FindTask(NULL);
  81.  
  82.     Port = &Me -> pr_MsgPort;
  83.  
  84.     WaitPort(Port);
  85.  
  86.     Buffer = (struct Buffer *)GetMsg(Port);
  87.  
  88.         /* Open the file and obtain a filehandle. */
  89.  
  90.     String = (STRPTR)Buffer -> ActionData[ARG_MODE];
  91.  
  92.     Buffer -> WriteAccess = TRUE;
  93.  
  94.         /* Put the message into the list. */
  95.  
  96.     ObtainSemaphore(&DoubleBufferSemaphore);
  97.  
  98.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  99.  
  100.     ReleaseSemaphore(&DoubleBufferSemaphore);
  101.  
  102.         /* Remember the opening date. */
  103.  
  104.     DateStamp(&Buffer -> OpenDate);
  105.  
  106.         /* Check for the open type. */
  107.  
  108.     switch(String[0])
  109.     {
  110.         case 'r':
  111.  
  112.             if(String[1] == '+')
  113.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  114.             else
  115.             {
  116.                 Buffer -> WriteAccess = FALSE;
  117.  
  118.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
  119.             }
  120.  
  121.             break;
  122.  
  123.         case 'w':
  124.  
  125.             if(String[1] == '+')
  126.             {
  127.                 if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  128.                 {
  129.                     UnLock(SomeLock);
  130.  
  131.                     DeleteFile((STRPTR)Buffer -> ActionData[ARG_NAME]);
  132.                 }
  133.  
  134.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  135.             }
  136.             else
  137.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  138.  
  139.             break;
  140.  
  141.         case 'a':
  142.  
  143.             if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  144.             {
  145.                 UnLock(SomeLock);
  146.  
  147.                 if(Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
  148.                 {
  149.                     if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  150.                     {
  151.                         Close(Buffer -> FileHandle);
  152.  
  153.                         Buffer -> FileHandle = NULL;
  154.                     }
  155.                 }
  156.             }
  157.             else
  158.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  159.  
  160.             break;
  161.     }
  162.  
  163.         /* Clear signal bit. */
  164.  
  165.     ClrSignal(SIG_COMMAND);
  166.  
  167.         /* Did the file open? */
  168.  
  169.     if(Buffer -> FileHandle)
  170.     {
  171.         Buffer -> Data        = Buffer -> DataBuffer[0];
  172.         Buffer -> DataCount    = 1;
  173.         Buffer -> Fresh        = TRUE;
  174.  
  175.             /* If not in write mode fill the buffers. */
  176.  
  177.         if(!Buffer -> WriteAccess)
  178.         {
  179.                 /* Fill the first one synchronously. */
  180.  
  181.             Buffer -> ReadBufFull    = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  182.             Buffer -> Read        = TRUE;
  183.             Buffer -> RealPosition    = Buffer -> ReadBufFull;
  184.  
  185.                 /* Restart caller. */
  186.  
  187.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  188.  
  189.                 /* Fill the second buffe asynchronously. */
  190.  
  191.             Buffer -> DataLength[1]    = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  192.             Buffer -> RealPosition += Buffer -> Cached;
  193.         }
  194.         else
  195.         {
  196.             Buffer -> InfoPort = ((struct FileHandle *)BADDR(Buffer -> FileHandle)) -> fh_Type;
  197.  
  198.             ObtainInfo(Buffer);
  199.  
  200.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  201.         }
  202.     }
  203.     else
  204.         Terminated = TRUE;
  205.  
  206.         /* Go into loop waiting for commands. */
  207.  
  208.     while(!Terminated)
  209.     {
  210.         Wait(SIG_COMMAND);
  211.  
  212.         Done = FALSE;
  213.  
  214.         Buffer -> Result = 0;
  215.  
  216.             /* Take care of each action. */
  217.  
  218.         switch(Buffer -> Action)
  219.         {
  220.                 /* Close the file, flush any dirty
  221.                  * buffers and exit.
  222.                  */
  223.  
  224.             case BUF_CLOSE:
  225.  
  226.                 Buffer -> Result = TRUE;
  227.  
  228.                 if(Buffer -> BufPosition && Buffer -> Written)
  229.                 {
  230.                     if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  231.                         Buffer -> Result = FALSE;
  232.                 }
  233.  
  234.                 if(!Close(Buffer -> FileHandle))
  235.                     Buffer -> Result = FALSE;
  236.  
  237.                 Terminated = TRUE;
  238.  
  239.                 break;
  240.  
  241.                 /* Seek to a specific file position. */
  242.  
  243.             case BUF_SEEK:
  244.  
  245.                 Buffer -> Result = 0;
  246.  
  247.                     /* Do nothing if buffer is still
  248.                      * untouched and we are required
  249.                      * to seek back to the beginning
  250.                      * of the file.
  251.                      */
  252.  
  253.                 if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEKFILE_SET)
  254.                 {
  255.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  256.  
  257.                     Done = TRUE;
  258.                 }
  259.                 else
  260.                 {
  261.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  262.                     Buffer -> Read        = FALSE;
  263.  
  264.                     if(Buffer -> BufPosition && Buffer -> Written)
  265.                     {
  266.                         if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  267.                             Buffer -> Result = -1;
  268.                         else
  269.                             ObtainInfo(Buffer);
  270.                     }
  271.  
  272.                     if(!Buffer -> Result)
  273.                     {
  274.                         Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
  275.  
  276.                         switch(Buffer -> ActionData[ARG_ORIGIN])
  277.                         {
  278.                             case SEEKFILE_SET:
  279.  
  280.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  281.                                     Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
  282.                                 else
  283.                                     Buffer -> Result = -1;
  284.  
  285.                                 break;
  286.  
  287.                             case SEEKFILE_CURR:
  288.  
  289.                                 if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
  290.                                 {
  291.                                     Buffer -> ReadBufFull    -= Buffer -> ActionData[ARG_OFFSET];
  292.                                     Buffer -> Data        += Buffer -> ActionData[ARG_OFFSET];
  293.  
  294.                                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  295.  
  296.                                     Done = TRUE;
  297.  
  298.                                     break;
  299.                                 }
  300.  
  301.                                 if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  302.                                     Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
  303.                                 else
  304.                                     Buffer -> Result = -1;
  305.  
  306.                                 break;
  307.  
  308.                             case SEEKFILE_END:
  309.  
  310.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
  311.                                     Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
  312.                                 else
  313.                                     Buffer -> Result = -1;
  314.  
  315.                                 break;
  316.  
  317.                             default:
  318.  
  319.                                 Buffer -> Result = -1;
  320.                         }
  321.  
  322.                         Buffer -> ReadBufFull = 0;
  323.  
  324.                         if(Buffer -> Result != -1)
  325.                         {
  326.                             Buffer -> Data        = Buffer -> DataBuffer[0];
  327.                             Buffer -> DataCount    = 1;
  328.  
  329.                             if(!Buffer -> WriteAccess)
  330.                             {
  331.                                 Buffer -> ReadBufFull     = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  332.                                 Buffer -> WriteBufFull     = 0;
  333.                                 Buffer -> Read         = TRUE;
  334.                                 Buffer -> RealPosition    += Buffer -> ReadBufFull;
  335.  
  336.                                 if(Buffer -> ReadBufFull)
  337.                                 {
  338.                                     Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  339.  
  340.                                     Buffer -> RealPosition += Buffer -> Cached;
  341.                                 }
  342.                             }
  343.                         }
  344.                         else
  345.                             Buffer -> LastActionFailed = TRUE;
  346.                     }
  347.                     else
  348.                         Buffer -> ReadBufFull = 0;
  349.  
  350.                     Buffer -> BufPosition    = 0;
  351.                     Buffer -> Written    = FALSE;
  352.                 }
  353.  
  354.                 break;
  355.  
  356.                 /* Fill the buffer with fresh data. */
  357.  
  358.             case BUF_FILL:
  359.  
  360.                 Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  361.                 Buffer -> ReadBufFull    = Buffer -> DataLength[Buffer -> DataCount];
  362.                 Buffer -> WriteBufFull    = 0;
  363.                 Buffer -> BufPosition    = 0;
  364.                 Buffer -> Read        = TRUE;
  365.                 Buffer -> Written    = FALSE;
  366.                 Buffer -> Fresh        = FALSE;
  367.  
  368.                 if(Buffer -> ReadBufFull)
  369.                     WasFull = TRUE;
  370.                 else
  371.                     WasFull = FALSE;
  372.  
  373.                     /* The buffer contents have been
  374.                      * swapped, now wake the caller
  375.                      * up and fill the next buffer
  376.                      * asynchronously.
  377.                      */
  378.  
  379.                 Signal(Buffer -> Caller,SIG_HANDSHAKE);
  380.  
  381.                 Done = TRUE;
  382.  
  383.                 if(WasFull)
  384.                 {
  385.                     Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  386.  
  387.                     Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
  388.  
  389.                     Buffer -> RealPosition += Buffer -> Cached;
  390.  
  391.                     if(!Buffer -> DataLength[Buffer -> DataCount])
  392.                     {
  393.                         if(IoErr())
  394.                             Buffer -> LastActionFailed = TRUE;
  395.                     }
  396.                 }
  397.  
  398.                 break;
  399.  
  400.                 /* Flush the contents of the buffer to disk. */
  401.  
  402.             case BUF_FLUSH:
  403.  
  404.                 if(Buffer -> BufPosition && Buffer -> Written)
  405.                 {
  406.                     Data            = Buffer -> Data;
  407.                     Length            = Buffer -> BufPosition;
  408.  
  409.                     Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  410.                     Buffer -> DataCount    = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  411.  
  412.                     Buffer -> ReadBufFull    = 0;
  413.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  414.                     Buffer -> BufPosition    = 0;
  415.                     Buffer -> Read        = FALSE;
  416.                     Buffer -> Written    = FALSE;
  417.  
  418.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  419.  
  420.                     Done = TRUE;
  421.  
  422.                     if(Write(Buffer -> FileHandle,Data,Length) != Length)
  423.                         Buffer -> LastActionFailed = TRUE;
  424.                     else
  425.                     {
  426.                         ObtainInfo(Buffer);
  427.  
  428.                         Buffer -> RealPosition += Length;
  429.                     }
  430.                 }
  431.                 else
  432.                 {
  433.                     Buffer -> ReadBufFull    = 0;
  434.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  435.                     Buffer -> BufPosition    = 0;
  436.                     Buffer -> Read        = FALSE;
  437.                     Buffer -> Written    = FALSE;
  438.                 }
  439.  
  440.                 Buffer -> Fresh = FALSE;
  441.  
  442.                 break;
  443.         }
  444.  
  445.             /* Ring back if necessary. */
  446.  
  447.         if(!Done && !Terminated)
  448.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  449.     }
  450.  
  451.         /* Remove the message from the list. */
  452.  
  453.     ObtainSemaphore(&DoubleBufferSemaphore);
  454.  
  455.     Remove((struct Node *)Buffer);
  456.  
  457.     ReleaseSemaphore(&DoubleBufferSemaphore);
  458.  
  459.         /* Lock & quit. */
  460.  
  461.     Forbid();
  462.  
  463.     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  464. }
  465.  
  466.     /* BufferFill(struct Buffer *Buffer):
  467.      *
  468.      *    Fills a given buffer with fresh data.
  469.      */
  470.  
  471. STATIC BOOL
  472. BufferFill(struct Buffer *Buffer)
  473. {
  474.     if(Buffer -> LastActionFailed)
  475.         return(FALSE);
  476.     else
  477.     {
  478.         if(!Buffer -> ReadBufFull)
  479.         {
  480.             Buffer -> Action = BUF_FILL;
  481.  
  482.             Forbid();
  483.  
  484.             Signal(Buffer -> Child,SIG_COMMAND);
  485.  
  486.             ClrSignal(SIG_HANDSHAKE);
  487.  
  488.             Wait(SIG_HANDSHAKE);
  489.  
  490.             Permit();
  491.         }
  492.  
  493.         return(TRUE);
  494.     }
  495. }
  496.  
  497.     /* IsValidBuffer(struct Buffer *Buffer):
  498.      *
  499.      *    Scans the double buffered file list for
  500.      *    a valid entry.
  501.      */
  502.  
  503. STATIC BOOL
  504. IsValidBuffer(struct Buffer *Buffer)
  505. {
  506.     BOOL         GotIt = FALSE;
  507.     struct Node    *Node;
  508.  
  509.     ObtainSemaphore(&DoubleBufferSemaphore);
  510.  
  511.     Node = DoubleBufferList . lh_Head;
  512.  
  513.     while(Node -> ln_Succ)
  514.     {
  515.         if(Buffer == (struct Buffer *)Node)
  516.         {
  517.             GotIt = TRUE;
  518.  
  519.             break;
  520.         }
  521.  
  522.         Node = Node -> ln_Succ;
  523.     }
  524.  
  525.     ReleaseSemaphore(&DoubleBufferSemaphore);
  526.  
  527.     return(GotIt);
  528. }
  529.  
  530.     /* OpenFileSimple(STRPTR Name,STRPTR AccessMode):
  531.      *
  532.      *    Open simple (unbuffered) file.
  533.      */
  534.  
  535. STATIC struct Buffer *
  536. OpenFileSimple(STRPTR Name,STRPTR AccessMode)
  537. {
  538.     struct Buffer *Buffer;
  539.  
  540.         /* Allocate buffer handle (dummy). */
  541.  
  542.     if(Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer),MEMF_ANY | MEMF_CLEAR))
  543.     {
  544.         BPTR SomeLock;
  545.  
  546.             /* Provide basic information. */
  547.  
  548.         DateStamp(&Buffer -> OpenDate);
  549.  
  550.         Buffer -> WriteAccess = TRUE;
  551.  
  552.         Buffer -> SimpleIO = TRUE;
  553.  
  554.             /* Open the file. */
  555.  
  556.         switch(AccessMode[0])
  557.         {
  558.             case 'r':
  559.  
  560.                 if(AccessMode[1] == '+')
  561.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  562.                 else
  563.                 {
  564.                     Buffer -> WriteAccess = FALSE;
  565.  
  566.                     Buffer -> FileHandle = Open(Name,MODE_OLDFILE);
  567.                 }
  568.  
  569.                 break;
  570.  
  571.             case 'w':
  572.  
  573.                 if(AccessMode[1] == '+')
  574.                 {
  575.                     if(SomeLock = Lock(Name,ACCESS_WRITE))
  576.                     {
  577.                         UnLock(SomeLock);
  578.  
  579.                         DeleteFile(Name);
  580.                     }
  581.  
  582.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  583.                 }
  584.                 else
  585.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  586.  
  587.                 break;
  588.  
  589.             case 'a':
  590.  
  591.                 if(SomeLock = Lock(Name,ACCESS_WRITE))
  592.                 {
  593.                     UnLock(SomeLock);
  594.  
  595.                     if(Buffer -> FileHandle = Open(Name,MODE_READWRITE))
  596.                     {
  597.                         if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  598.                         {
  599.                             Close(Buffer -> FileHandle);
  600.  
  601.                             Buffer -> FileHandle = NULL;
  602.                         }
  603.                     }
  604.                 }
  605.                 else
  606.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  607.  
  608.                 break;
  609.         }
  610.  
  611.             /* Did we succeed in opening the file? */
  612.  
  613.         if(Buffer -> FileHandle)
  614.         {
  615.                 /* To keep track of the free space still
  616.                  * available on the filing system.
  617.                  */
  618.  
  619.             if(Buffer -> WriteAccess)
  620.             {
  621.                 Buffer -> InfoPort = ((struct FileHandle *)BADDR(Buffer -> FileHandle)) -> fh_Type;
  622.  
  623.                 ObtainInfo(Buffer);
  624.             }
  625.  
  626.                 /* Link the file into the list. */
  627.  
  628.             ObtainSemaphore(&DoubleBufferSemaphore);
  629.  
  630.             AddTail(&DoubleBufferList,(struct Node *)Buffer);
  631.  
  632.             ReleaseSemaphore(&DoubleBufferSemaphore);
  633.  
  634.             return(Buffer);
  635.         }
  636.         else
  637.             FreeVecPooled(Buffer);
  638.     }
  639.  
  640.     return(NULL);
  641. }
  642.  
  643.     /* OpenFileBuffered(STRPTR Name,STRPTR AccessMode):
  644.      *
  645.      *    Open double-buffered file.
  646.      */
  647.  
  648. STATIC struct Buffer *
  649. OpenFileBuffered(STRPTR Name,STRPTR AccessMode)
  650. {
  651.     struct Buffer    *Buffer;
  652.     LONG         Size;
  653.  
  654.     Size = (Config -> MiscConfig -> IOBufferSize + 15) & ~15;
  655.  
  656.     if(Size < 2048)
  657.         Size = 2048;
  658.  
  659.         /* Allocate the buffer data. */
  660.  
  661.     do
  662.     {
  663.         Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer) + ((Size + 15) & ~15) * BUFFER_NUMBER + 15,MEMF_ANY | MEMF_CLEAR);
  664.  
  665.         Size /= 2;
  666.     }
  667.     while(!Buffer && Size > 2048);
  668.  
  669.     if(Buffer)
  670.     {
  671.         struct Process    *Process;
  672.         LONG         i;
  673.  
  674.             /* Set up the first buffer. */
  675.  
  676.         Buffer -> DataBuffer[0] = (UBYTE *)(((ULONG)(Buffer + 1) + 15) & ~15);
  677.  
  678.             /* Set up the individual buffers. */
  679.  
  680.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  681.             Buffer -> DataBuffer[i] = Buffer -> DataBuffer[i - 1] + Size;
  682.  
  683.         Buffer -> BufLength    = Size;
  684.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  685.  
  686.             /* Create the asynchronous file server. */
  687.  
  688.         if(!(Process = CreateNewProcTags(
  689.             NP_Entry,    FileBufferServer,
  690.             NP_Name,    "term File Process",
  691.             NP_WindowPtr,    -1,
  692.         TAG_DONE)))
  693.         {
  694.             FreeVecPooled(Buffer);
  695.  
  696.             return(NULL);
  697.         }
  698.  
  699.             /* Set up the message header. */
  700.  
  701.         Buffer -> Message . mn_Length    = sizeof(struct Buffer);
  702.  
  703.         Buffer -> ActionData[ARG_NAME]    = (LONG)Name;
  704.         Buffer -> ActionData[ARG_MODE]    = (LONG)AccessMode;
  705.  
  706.         Buffer -> Child            = Process;
  707.         Buffer -> Caller        = (struct Process *)FindTask(NULL);
  708.  
  709.         Forbid();
  710.  
  711.             /* Send it to the waiting server process. */
  712.  
  713.         PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
  714.  
  715.             /* Wait for ringback. */
  716.  
  717.         ClrSignal(SIG_HANDSHAKE);
  718.  
  719.         Wait(SIG_HANDSHAKE);
  720.  
  721.         Permit();
  722.  
  723.             /* Do we have a valid filehandle? */
  724.  
  725.         if(!Buffer -> FileHandle)
  726.         {
  727.             FreeVecPooled(Buffer);
  728.  
  729.             return(NULL);
  730.         }
  731.         else
  732.             return(Buffer);
  733.     }
  734.  
  735.     return(NULL);
  736. }
  737.  
  738.     /* BPrintf():
  739.      *
  740.      *    Prints text into a buffered file.
  741.      */
  742.  
  743. LONG __stdargs
  744. BPrintf(struct Buffer *Buffer,STRPTR Format,...)
  745. {
  746.     UBYTE    String[256];
  747.     va_list    VarArgs;
  748.  
  749.     va_start(VarArgs,Format);
  750.     VSPrintf(String,Format,VarArgs);
  751.     va_end(VarArgs);
  752.  
  753.     return(BufferWrite(Buffer,String,strlen(String)));
  754. }
  755.  
  756.     /* BufferFlush(struct Buffer *Buffer):
  757.      *
  758.      *    Flush the contents of a given buffer to disk.
  759.      */
  760.  
  761. BOOL
  762. BufferFlush(struct Buffer *Buffer)
  763. {
  764.     if(Buffer -> LastActionFailed)
  765.         return(FALSE);
  766.     else
  767.     {
  768.         if(Buffer -> BufPosition && Buffer -> Written)
  769.         {
  770.             Buffer -> Action = BUF_FLUSH;
  771.  
  772.             Forbid();
  773.  
  774.             Signal(Buffer -> Child,SIG_COMMAND);
  775.  
  776.             ClrSignal(SIG_HANDSHAKE);
  777.  
  778.             Wait(SIG_HANDSHAKE);
  779.  
  780.             Permit();
  781.         }
  782.  
  783.         return(TRUE);
  784.     }
  785. }
  786.  
  787.     /* BufferClose(struct Buffer *Buffer):
  788.      *
  789.      *    Close a buffered filehandle.
  790.      */
  791.  
  792. BOOL
  793. BufferClose(struct Buffer *Buffer)
  794. {
  795.     if(IsValidBuffer(Buffer))
  796.     {
  797.         BOOL Success;
  798.  
  799.             /* Unbuffered file handle? */
  800.  
  801.         if(Buffer -> SimpleIO)
  802.         {
  803.                 /* Close the file. */
  804.  
  805.             if(Close(Buffer -> FileHandle))
  806.                 Success = TRUE;
  807.             else
  808.                 Success = FALSE;
  809.  
  810.                 /* Unlink the handle. */
  811.  
  812.             ObtainSemaphore(&DoubleBufferSemaphore);
  813.  
  814.             Remove((struct Node *)Buffer);
  815.  
  816.             ReleaseSemaphore(&DoubleBufferSemaphore);
  817.         }
  818.         else
  819.         {
  820.             Buffer -> Action = BUF_CLOSE;
  821.  
  822.             Forbid();
  823.  
  824.             Signal(Buffer -> Child,SIG_COMMAND);
  825.  
  826.             ClrSignal(SIG_HANDSHAKE);
  827.  
  828.             Wait(SIG_HANDSHAKE);
  829.  
  830.             Permit();
  831.  
  832.             Success = Buffer -> Result;
  833.         }
  834.  
  835.         FreeVecPooled(Buffer);
  836.  
  837.         return(Success);
  838.     }
  839.     else
  840.         return(FALSE);
  841. }
  842.  
  843.     /* BufferOpen(STRPTR Name,STRPTR AccessMode):
  844.      *
  845.      *    Open a file for buffered I/O.
  846.      */
  847.  
  848. struct Buffer *
  849. BufferOpen(STRPTR Name,STRPTR AccessMode)
  850. {
  851.         /* Simple file handling? */
  852.  
  853.     if(Config -> MiscConfig -> SimpleIO)
  854.         return(OpenFileSimple(Name,AccessMode));
  855.     else
  856.     {
  857.         struct Buffer *Buffer;
  858.  
  859.             /* Try to open a buffered file, if unsuccessful
  860.              * fall back to simple file I/O.
  861.              */
  862.  
  863.         if(!(Buffer = OpenFileBuffered(Name,AccessMode)))
  864.             Buffer = OpenFileSimple(Name,AccessMode);
  865.  
  866.         return(Buffer);
  867.     }
  868. }
  869.  
  870.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  871.      *
  872.      *    Move the read/write pointer to a specific position
  873.      *    in a file (not really buffered).
  874.      */
  875.  
  876. BOOL
  877. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  878. {
  879.     if(Buffer -> SimpleIO)
  880.     {
  881.         if(Seek(Buffer -> FileHandle,Offset,Origin) == -1)
  882.             return(FALSE);
  883.         else
  884.             return(TRUE);
  885.     }
  886.     else
  887.     {
  888.         Buffer -> Action            = BUF_SEEK;
  889.         Buffer -> ActionData[ARG_OFFSET]    = Offset;
  890.         Buffer -> ActionData[ARG_ORIGIN]    = Origin;
  891.  
  892.         Forbid();
  893.  
  894.         Signal(Buffer -> Child,SIG_COMMAND);
  895.  
  896.         ClrSignal(SIG_HANDSHAKE);
  897.  
  898.         Wait(SIG_HANDSHAKE);
  899.  
  900.         Permit();
  901.  
  902.         if(Buffer -> Result == -1)
  903.             return(FALSE);
  904.         else
  905.             return(TRUE);
  906.     }
  907. }
  908.  
  909.     /* BufferRead():
  910.      *
  911.      *    Read data from a file (buffered).
  912.      */
  913.  
  914. LONG
  915. BufferRead(struct Buffer *Buffer,STRPTR Destination,LONG Size)
  916. {
  917.     if(Buffer -> SimpleIO)
  918.     {
  919.         LONG Bytes;
  920.  
  921.         Buffer -> Used = TRUE;
  922.  
  923.         if((Bytes = Read(Buffer -> FileHandle,Destination,Size)) < 0)
  924.             Bytes = 0;
  925.  
  926.         return(Bytes);
  927.     }
  928.     else
  929.     {
  930.         LONG     BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
  931.         UBYTE    *Data;
  932.  
  933.             /* If there is still data to be written in
  934.              * the buffer, write it.
  935.              */
  936.  
  937.         if(Buffer -> Written)
  938.         {
  939.             if(!BufferFlush(Buffer))
  940.                 return(0);
  941.         }
  942.  
  943.             /* Set up for read access. */
  944.  
  945.         BufPosition    = Buffer -> BufPosition;
  946.         ReadBufFull    = Buffer -> ReadBufFull;
  947.         Data        = &Buffer -> Data[BufPosition];
  948.  
  949.             /* Remember access. */
  950.  
  951.         Buffer -> Used    = TRUE;
  952.  
  953.             /* Continue until all data has been processed. */
  954.  
  955.         while(Size)
  956.         {
  957.                 /* Determine number of bytes to transfer. */
  958.  
  959.             if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  960.             {
  961.                 CopyMem(Data,Destination,ToCopy);
  962.  
  963.                 Size        -= ToCopy;
  964.                 BufPosition    += ToCopy;
  965.                 ReadBufFull    -= ToCopy;
  966.                 Destination    += ToCopy;
  967.                 Data        += ToCopy;
  968.                 BytesRead    += ToCopy;
  969.             }
  970.             else
  971.             {
  972.                     /* Refill buffer with data. */
  973.  
  974.                 Buffer -> BufPosition    = BufPosition;
  975.                 Buffer -> ReadBufFull    = ReadBufFull;
  976.  
  977.                 if(!BufferFill(Buffer))
  978.                     return(BytesRead);
  979.  
  980.                 if(!Buffer -> ReadBufFull)
  981.                 {
  982.                     Buffer -> BufPosition = BufPosition;
  983.  
  984.                     return(BytesRead);
  985.                 }
  986.  
  987.                     /* Pick up new data. */
  988.  
  989.                 BufPosition        = Buffer -> BufPosition;
  990.                 ReadBufFull        = Buffer -> ReadBufFull;
  991.                 Data            = Buffer -> Data;
  992.             }
  993.         }
  994.  
  995.             /* Install new data. */
  996.  
  997.         Buffer -> BufPosition    = BufPosition;
  998.         Buffer -> ReadBufFull    = ReadBufFull;
  999.  
  1000.         return(BytesRead);
  1001.     }
  1002. }
  1003.  
  1004.     /* BufferWrite():
  1005.      *
  1006.      *    Write data to a file (buffered).
  1007.      */
  1008.  
  1009. LONG
  1010. BufferWrite(struct Buffer *Buffer,STRPTR Source,LONG Size)
  1011. {
  1012.     if(Buffer -> SimpleIO)
  1013.     {
  1014.         LONG Bytes;
  1015.  
  1016.         Buffer -> Used = TRUE;
  1017.  
  1018.         Buffer -> WriteAccess = TRUE;
  1019.  
  1020.         if((Bytes = Write(Buffer -> FileHandle,Source,Size)) < 0)
  1021.             Bytes = 0;
  1022.         else
  1023.         {
  1024.             Buffer -> BufPosition += Bytes;
  1025.  
  1026.             if(Buffer -> BufPosition >= Config -> MiscConfig -> IOBufferSize)
  1027.             {
  1028.                 Buffer -> BufPosition = 0;
  1029.  
  1030.                 ObtainInfo(Buffer);
  1031.             }
  1032.         }
  1033.  
  1034.         return(Bytes);
  1035.     }
  1036.     else
  1037.     {
  1038.         LONG     BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
  1039.         UBYTE    *Data;
  1040.  
  1041.             /* If there is still read data in the buffer,
  1042.              * reset the control information.
  1043.              */
  1044.  
  1045.         if(Buffer -> Read)
  1046.         {
  1047.             Buffer -> WriteBufFull    = Buffer -> BufLength;
  1048.             Buffer -> BufPosition    = 0;
  1049.             Buffer -> Read        = FALSE;
  1050.         }
  1051.  
  1052.             /* Set up for write access. */
  1053.  
  1054.         Buffer -> Written = TRUE;
  1055.  
  1056.         BufPosition    = Buffer -> BufPosition;
  1057.         WriteBufFull    = Buffer -> WriteBufFull;
  1058.         Data        = &Buffer -> Data[BufPosition];
  1059.  
  1060.             /* Remember access. */
  1061.  
  1062.         Buffer -> Used    = TRUE;
  1063.  
  1064.             /* Continue until all data has been processed. */
  1065.  
  1066.         while(Size)
  1067.         {
  1068.                 /* Determine number of bytes to transfer. */
  1069.  
  1070.             if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  1071.             {
  1072.                 CopyMem(Source,Data,ToCopy);
  1073.  
  1074.                 Size        -= ToCopy;
  1075.                 BufPosition    += ToCopy;
  1076.                 WriteBufFull    -= ToCopy;
  1077.                 Source        += ToCopy;
  1078.                 Data        += ToCopy;
  1079.                 BytesWritten    += ToCopy;
  1080.             }
  1081.             else
  1082.             {
  1083.                     /* Flush the contents of the
  1084.                      * write buffer.
  1085.                      */
  1086.  
  1087.                 Buffer -> BufPosition    = BufPosition;
  1088.                 Buffer -> WriteBufFull    = WriteBufFull;
  1089.  
  1090.                 if(!BufferFlush(Buffer))
  1091.                     return(BytesWritten);
  1092.  
  1093.                     /* Pick up new data. */
  1094.  
  1095.                 BufPosition        = Buffer -> BufPosition;
  1096.                 WriteBufFull        = Buffer -> WriteBufFull;
  1097.                 Data            = Buffer -> Data;
  1098.  
  1099.                     /* Important - or BufferFlush() won't
  1100.                      * write the final buffer contents when
  1101.                      * the buffered file handle is freed up.
  1102.                      */
  1103.  
  1104.                 Buffer -> Written = TRUE;
  1105.             }
  1106.         }
  1107.  
  1108.             /* Install new data. */
  1109.  
  1110.         Buffer -> BufPosition    = BufPosition;
  1111.         Buffer -> WriteBufFull    = WriteBufFull;
  1112.  
  1113.         return(BytesWritten);
  1114.     }
  1115. }
  1116.